package com.dd.keel.core.common.utils;

/**
 * Provide some hash algorithms
 * 
 * @author Kevin.XU
 * 
 */
public class HashUtil {
	
	public static long RSHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}			
		int b = 378551;
		int a = 63689;
		long hash = 0;
		for (int i = 0; i < str.length(); i++) {
			hash = hash * a + str.charAt(i);
			a = a * b;
		}
		return hash;
	}

	public static long JSHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}	
		long hash = 1315423911;
		for (int i = 0; i < str.length(); i++) {
			hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
		}
		return hash;
	}

	public static long PJWHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}	
		long BitsInUnsignedInt = (long) (4 * 8);
		long ThreeQuarters = (long) ((BitsInUnsignedInt * 3) / 4);
		long OneEighth = (long) (BitsInUnsignedInt / 8);
		long HighBits = (long) (0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
		long hash = 0;
		long test = 0;
		for (int i = 0; i < str.length(); i++) {
			hash = (hash << OneEighth) + str.charAt(i);
			if ((test = hash & HighBits) != 0) {
				hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
			}
		}
		return hash;
	}

	public static long ELFHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}			
		long hash = 0;
		long x = 0;
		for (int i = 0; i < str.length(); i++) {
			hash = (hash << 4) + str.charAt(i);
			if ((x = hash & 0xF0000000L) != 0) {
				hash ^= (x >> 24);
			}
			hash &= ~x;
		}
		return hash;
	}

	public static long BKDRHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}	
		long seed = 131; // 31 131 1313 13131 131313 etc..
		long hash = 0;
		for (int i = 0; i < str.length(); i++) {
			hash = (hash * seed) + str.charAt(i);
		}
		return hash;
	}

	public static long SDBMHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}	
		long hash = 0;
		for (int i = 0; i < str.length(); i++) {
			hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
		}
		return hash;
	}

	public static long DJBHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}	
		long hash = 5381;
		for (int i = 0; i < str.length(); i++) {
			hash = ((hash << 5) + hash) + str.charAt(i);
		}
		return hash;
	}

	public static long DEKHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}			
		long hash = str.length();
		for (int i = 0; i < str.length(); i++) {
			hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
		}
		return hash;
	}

	public static long BPHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}	
		long hash = 0;
		for (int i = 0; i < str.length(); i++) {
			hash = hash << 7 ^ str.charAt(i);
		}
		return hash;
	}

	public static long FNVHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}	
		long fnv_prime = 0x811C9DC5;
		long hash = 0;
		for (int i = 0; i < str.length(); i++) {
			hash *= fnv_prime;
			hash ^= str.charAt(i);
		}
		return hash;
	}

	public static long APHash(String str) 
	{
		if (str == null || str.length() == 0) {
			return -1;
		}			
		long hash = 0xAAAAAAAA;
		for (int i = 0; i < str.length(); i++) {
			if ((i & 1) == 0) {
				hash ^= ((hash << 7) ^ str.charAt(i) ^ (hash >> 3));
			} else {
				hash ^= (~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));
			}
		}
		return hash;
	}
	
	public static long simpleHash(String str)
	{
		if (str == null || str.length() == 0) {
			return -1;
		}		
		long hash = 0;
		for (int i = 0; i < str.length(); ++i) {
			hash += str.charAt(i);
		}
		return hash;
	}
	
	/**
	 * 取模
	 * @param hash
	 * @param prime
	 * @return
	 */
	public static long mode(long hash, int prime)
	{
		return hash % prime;
	}
	
	/**
	 * 将一个字符串取hash值并按照一个质数取模
	 * 
	 * @param str
	 * @param prime
	 * @return
	 */
	public static long ELFhashMode(String str, int prime) 
	{
		long hash = ELFHash(str);
		if(hash==-1)
		{
			return -1;
		}
		return mode(hash,prime);
	}
	
}
